package org.streets.database;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A simple DriverManager DataSource implementation
 * 
 * @author dzb
 */
public class DriverManagerDataSource implements DataSource{

	private ConnectionConfigurer _cfg = null;
    private PrintWriter _writer;
    private int timeout = 60;
	private final ArrayList<Connection> pool = new ArrayList<Connection>();
	private int poolSize = 5;

	private int checkedOut = 0;
	
	private static final Logger log = LoggerFactory.getLogger(DriverManagerDataSource.class);
    /**
     * 
     * @param cc
     */
    public DriverManagerDataSource(ConnectionConfigurer cc) {
    	_cfg = cc;
        try {
            Class.forName(_cfg.getDriverName());
        } catch (ClassNotFoundException e) {
            throw new SQLNestedException("Cannot load driver.", e);
        }
    }
    /**
     *
     * @param driver
     * @param url
     * @param user
     * @param password
     * @throws IllegalArgumentException If the driver cannot be instantiated.
     */
    public DriverManagerDataSource(String driver, String url, String user, String password) {
    	_cfg = new ConnectionConfigurer(driver, url, user, password);
        try {
            Class.forName(_cfg.getDriverName());
        } catch (ClassNotFoundException e) {
            throw new SQLNestedException("Cannot load driver.", e);
        }
    }
    
    /**
     * Not supported.
     * @return 0
     * @throws SQLException Never.
     */
    public int getLoginTimeout() throws SQLException {
        return timeout;
    }
    /**
     * Not supported.
     * @throws SQLException Never.
     */
    public void setLoginTimeout(int seconds) throws SQLException {
    	timeout = seconds;
    }
    /**
     * Not supported.
     * @throws SQLException Never.
     */
    public PrintWriter getLogWriter() throws SQLException {
        return _writer;
    }
    /**
     * Not supported.
     * @throws SQLException Never.
     */
    public void setLogWriter(PrintWriter out) throws SQLException {
    	this._writer = out;
    }
    
	public int getPoolSize() {
		return poolSize;
	}
	
	public void setPoolSize(int poolSize) {
		this.poolSize = poolSize;
	}

    public Connection getConnection() throws SQLException {
		if ( log.isTraceEnabled() ) log.trace( "total checked-out connections: " + checkedOut );

		synchronized (pool) {
			if ( !pool.isEmpty() ) {
				int last = pool.size() - 1;
				if ( log.isTraceEnabled() ) {
					log.trace("using pooled JDBC connection, pool size: " + last);
					checkedOut++;
				}
				Connection pooled = pool.remove(last);
				return pooled;
			}
		}

		log.debug("opening new JDBC connection");
		Connection connection = DriverManager.getConnection(_cfg.getUrl(), _cfg.getUser(), _cfg.getPassword());

		if ( log.isDebugEnabled() ) {
			log.debug( "created connection to: " + _cfg.getUrl() + ", Isolation Level: " + connection.getTransactionIsolation() );
		}
		if ( log.isTraceEnabled() ) checkedOut++;

		return connection;
    }

    public Connection getConnection(String username, String password) throws SQLException {
        return DriverManager.getConnection(_cfg.getUrl(), username, password);
    }

	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return false;
	}

	public <T> T unwrap(Class<T> iface) throws SQLException {
		return null;
	}
}
